
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 *版权所有2002-2023原作者。
 *
 *根据Apache许可证2.0版许可（“许可证”）；
 *除非符合许可证的规定，否则您不得使用此文件。
 *您可以在以下网址获取许可证副本：
 *
 *https://www.apache.org/licenses/LICENSE-2.0
 *
 *除非适用法律要求或书面同意，软件
 *根据许可证进行的分发是在“按原样”的基础上进行的，
 *无任何明示或暗示的保证或条件。
 *有关管理权限的特定语言，请参阅许可证和
 *许可证下的限制。
 */

package org.springframework.validation;

import java.beans.PropertyEditor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessException;
import org.springframework.beans.PropertyAccessorUtils;
import org.springframework.beans.PropertyBatchUpdateException;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.format.Formatter;
import org.springframework.format.support.FormatterPropertyEditorAdapter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

/**
 * Binder that allows for setting property values on a target object, including
 * support for validation and binding result analysis.
 *
 * <p>The binding process can be customized by specifying allowed field patterns,
 * required fields, custom editors, etc.
 *
 * <p><strong>WARNING</strong>: Data binding can lead to security issues by exposing
 * parts of the object graph that are not meant to be accessed or modified by
 * external clients. Therefore, the design and use of data binding should be considered
 * carefully with regard to security. For more details, please refer to the dedicated
 * sections on data binding for
 * <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-initbinder-model-design">Spring Web MVC</a> and
 * <a href="https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-initbinder-model-design">Spring WebFlux</a>
 * in the reference manual.
 *
 * <p>The binding results can be examined via the {@link BindingResult} interface,
 * extending the {@link Errors} interface: see the {@link #getBindingResult()} method.
 * Missing fields and property access exceptions will be converted to {@link FieldError FieldErrors},
 * collected in the Errors instance, using the following error codes:
 *
 * <ul>
 * <li>Missing field error: "required"
 * <li>Type mismatch error: "typeMismatch"
 * <li>Method invocation error: "methodInvocation"
 * </ul>
 *
 * <p>By default, binding errors get resolved through the {@link BindingErrorProcessor}
 * strategy, processing for missing fields and property access exceptions: see the
 * {@link #setBindingErrorProcessor} method. You can override the default strategy
 * if needed, for example to generate different error codes.
 *
 * <p>Custom validation errors can be added afterwards. You will typically want to resolve
 * such error codes into proper user-visible error messages; this can be achieved through
 * resolving each error via a {@link org.springframework.context.MessageSource}, which is
 * able to resolve an {@link ObjectError}/{@link FieldError} through its
 * {@link org.springframework.context.MessageSource#getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)}
 * method. The list of message codes can be customized through the {@link MessageCodesResolver}
 * strategy: see the {@link #setMessageCodesResolver} method. {@link DefaultMessageCodesResolver}'s
 * javadoc states details on the default resolution rules.
 *
 * <p>This generic data binder can be used in any kind of environment.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @author Stephane Nicoll
 * @author Kazuki Shimizu
 * @author Sam Brannen
 * @see #setAllowedFields
 * @see #setRequiredFields
 * @see #registerCustomEditor
 * @see #setMessageCodesResolver
 * @see #setBindingErrorProcessor
 * @see #bind
 * @see #getBindingResult
 * @see DefaultMessageCodesResolver
 * @see DefaultBindingErrorProcessor
 * @see org.springframework.context.MessageSource
 */
/**
 *允许在目标对象上设置属性值的活页夹，包括
 *支持验证和绑定结果分析。
 *
 *<p>绑定过程可以通过指定允许的字段模式来定制，
 *必填字段、自定义编辑器等。
 *
 *<p><strong>警告</strong>：数据绑定可能会通过暴露
 *对象图中不打算由访问或修改的部分
 *外部客户端。因此，应考虑数据绑定的设计和使用
 *在安全方面要小心。有关更多详细信息，请参阅
 *的数据绑定部分
 *<a href=“https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann initbinder模型设计“>Spring Web MVC</a>和
 *<a href=“https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann initbinder模型设计“>Spring WebFlux</a>
 *在参考手册中。
 *
 *<p>绑定结果可以通过{@linkBindingResult}接口进行检查，
 *扩展{@linkErrors}接口：请参阅{@link#getBindingResult（）}方法。
 *缺少的字段和属性访问异常将转换为｛@link FieldError FieldErrors｝，
 *收集在Errors实例中，使用以下错误代码：
 *
 *<ul>
 *<li>缺少字段错误：“必需”
 *<li>类型不匹配错误：“typeMismatch”
 *<li>方法调用错误：“methodInvocation”
 *</ul>
 *
 *＜p＞默认情况下，绑定错误通过｛@link BindingErrorProcessor｝解决
 *策略，处理丢失的字段和属性访问异常：请参阅
 *｛@link#setBindingErrorProcessor｝方法。您可以覆盖默认策略
 *例如生成不同的错误代码。
 *
 *<p>之后可以添加自定义验证错误。您通常希望解决
 *这样的错误代码转换成适当的用户可见的错误消息；这可以通过
 *通过{@linkorg.springframework.context.MessageSource}解决每个错误
 *能够通过其
 *｛@link org.springframework.context.MessageSource#getMessage（org.springfframework.contect.MessageSourceResolutible，java.util.Locale）｝
 *方法。消息代码列表可以通过｛@link MessageCodesResolver｝自定义
 *策略：请参阅｛@link#setMessageCodesResolver｝方法。｛@link DefaultMessageCodesResolver｝的
 *javadoc详细说明了默认解析规则。
 *
 *<p>此通用数据绑定器可用于任何类型的环境。
 *
 *@作者罗德·约翰逊
 *@作者于尔根·霍勒
 *@作者Rob Harrop
 *@作者Stephane Nicoll
 *@作者清水和树
 *@作者Sam Brannen
 *@参见#setAllowedFields
 *@参见#setRequiredFields
 *@参见#registerCustomEditor
 *@参见#setMessageCodesResolver
 *@参见#setBindingErrorProcessor
 *@见#bind
 *@参见#getBindingResult
 *@请参阅DefaultMessageCodesResolver
 *@请参阅DefaultBindingErrorProcessor
 *@参见org.springframework.context.MessageSource
 */
public class DataBinder implements PropertyEditorRegistry, TypeConverter {

	/** Default object name used for binding: "target". */
	public static final String DEFAULT_OBJECT_NAME = "target";

	/** Default limit for array and collection growing: 256. */
	public static final int DEFAULT_AUTO_GROW_COLLECTION_LIMIT = 256;


	/**
	 * We'll create a lot of DataBinder instances: Let's use a static logger.
	 */
	/** Default object name used for binding: "target". */
	public static最终字符串DEFAULT_OBJECT_NAME=“target”；

	/**阵列和集合增长的默认限制：256*/
	公共静态最终int DEFAULT_AUTO_GROW_COLLECTION_LIMIT=256；


	/**
	 *我们将创建许多DataBinder实例：让我们使用静态记录器。
	 */
	protected static final Log logger = LogFactory.getLog(DataBinder.class);

	@Nullable
	private final Object target;

	private final String objectName;

	@Nullable
	private AbstractPropertyBindingResult bindingResult;

	private boolean directFieldAccess = false;

	@Nullable
	private SimpleTypeConverter typeConverter;

	private boolean ignoreUnknownFields = true;

	private boolean ignoreInvalidFields = false;

	private boolean autoGrowNestedPaths = true;

	private int autoGrowCollectionLimit = DEFAULT_AUTO_GROW_COLLECTION_LIMIT;

	@Nullable
	private String[] allowedFields;

	@Nullable
	private String[] disallowedFields;

	@Nullable
	private String[] requiredFields;

	@Nullable
	private ConversionService conversionService;

	@Nullable
	private MessageCodesResolver messageCodesResolver;

	private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor();

	private final List<Validator> validators = new ArrayList<>();


	/**
	 * Create a new DataBinder instance, with default object name.
	 * @param target the target object to bind onto (or {@code null}
	 * if the binder is just used to convert a plain parameter value)
	 * @see #DEFAULT_OBJECT_NAME
	 */
	/**
	 *使用默认对象名称创建一个新的DataBinder实例。
	 *@param target要绑定到的目标对象（或｛@code null｝
	 *如果绑定器仅用于转换普通参数值）
	 *@参见#DEFAULT_OBJECT_NAME
	 */
	public DataBinder(@Nullable Object target) {
		this(target, DEFAULT_OBJECT_NAME);
	}

	/**
	 * Create a new DataBinder instance.
	 * @param target the target object to bind onto (or {@code null}
	 * if the binder is just used to convert a plain parameter value)
	 * @param objectName the name of the target object
	 */
	/**
	 *创建一个新的DataBinder实例。
	 *@param target要绑定到的目标对象（或｛@code null｝
	 *如果绑定器仅用于转换普通参数值）
	 *@param objectName目标对象的名称
	 */
	public DataBinder(@Nullable Object target, String objectName) {
		this.target = ObjectUtils.unwrapOptional(target);
		this.objectName = objectName;
	}


	/**
	 * Return the wrapped target object.
	 */
	/**
	 *返回包裹的目标对象。
	 */
	@Nullable
	public Object getTarget() {
		return this.target;
	}

	/**
	 * Return the name of the bound object.
	 */
	/**
	 *返回绑定对象的名称。
	 */
	public String getObjectName() {
		return this.objectName;
	}

	/**
	 * Set whether this binder should attempt to "auto-grow" a nested path that contains a null value.
	 * <p>If "true", a null path location will be populated with a default object value and traversed
	 * instead of resulting in an exception. This flag also enables auto-growth of collection elements
	 * when accessing an out-of-bounds index.
	 * <p>Default is "true" on a standard DataBinder. Note that since Spring 4.1 this feature is supported
	 * for bean property access (DataBinder's default mode) and field access.
	 * @see #initBeanPropertyAccess()
	 * @see org.springframework.beans.BeanWrapper#setAutoGrowNestedPaths
	 */
	/**
	 *设置此绑定器是否应尝试“自动增长”包含空值的嵌套路径。
	 *<p>如果为“true”，将使用默认对象值填充空路径位置并遍历
	 *而不是导致异常。此标志还允许集合元素的自动增长
	 *访问越界索引时。
	 *<p>在标准DataBinder上，默认值为“true”。请注意，由于Spring 4.1支持此功能
	 *用于bean属性访问（DataBinder的默认模式）和字段访问。
	 *@参见#initBeanPropertyAccess（）
	 *@参见org.springframework.beans.BeanWrapper#setAutoGrowNestedPaths
	 */
	public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) {
		Assert.state(this.bindingResult == null,
				"DataBinder is already initialized - call setAutoGrowNestedPaths before other configuration methods");
		this.autoGrowNestedPaths = autoGrowNestedPaths;
	}

	/**
	 * Return whether "auto-growing" of nested paths has been activated.
	 */
	/**
	 *返回嵌套路径的“自动增长”是否已激活。
	 */
	public boolean isAutoGrowNestedPaths() {
		return this.autoGrowNestedPaths;
	}

	/**
	 * Specify the limit for array and collection auto-growing.
	 * <p>Default is 256, preventing OutOfMemoryErrors in case of large indexes.
	 * Raise this limit if your auto-growing needs are unusually high.
	 * @see #initBeanPropertyAccess()
	 * @see org.springframework.beans.BeanWrapper#setAutoGrowCollectionLimit
	 */
	/**
	 *指定阵列和集合自动增长的限制。
	 *<p>默认值为256，在索引较大的情况下可防止OutOfMemoryErrors。
	 *如果您的自动增长需求异常高，请提高此限制。
	 *@参见#initBeanPropertyAccess（）
	 *@参见org.springframework.beans.BeanWrapper#setAutoGrowCollectionLimit
	 */
	public void setAutoGrowCollectionLimit(int autoGrowCollectionLimit) {
		Assert.state(this.bindingResult == null,
				"DataBinder is already initialized - call setAutoGrowCollectionLimit before other configuration methods");
		this.autoGrowCollectionLimit = autoGrowCollectionLimit;
	}

	/**
	 * Return the current limit for array and collection auto-growing.
	 */
	/**
	 *返回数组和集合自动增长的当前限制。
	 */
	public int getAutoGrowCollectionLimit() {
		return this.autoGrowCollectionLimit;
	}

	/**
	 * Initialize standard JavaBean property access for this DataBinder.
	 * <p>This is the default; an explicit call just leads to eager initialization.
	 * @see #initDirectFieldAccess()
	 * @see #createBeanPropertyBindingResult()
	 */
	/**
	 *初始化此DataBinder的标准JavaBean属性访问。
	 *<p>这是默认值；显式调用只会导致急切的初始化。
	 *@参见#initDirectFieldAccess（）
	 *@参见#createBeanPropertyBindingResult（）
	 */
	public void initBeanPropertyAccess() {
		Assert.state(this.bindingResult == null,
				"DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
		this.directFieldAccess = false;
	}

	/**
	 * Create the {@link AbstractPropertyBindingResult} instance using standard
	 * JavaBean property access.
	 * @since 4.2.1
	 */
	/**
	 *使用标准创建｛@link AbstractPropertyBindingResult｝实例
	 *JavaBean属性访问。
	 *@自4.2.1起
	 */
	protected AbstractPropertyBindingResult createBeanPropertyBindingResult() {
		BeanPropertyBindingResult result = new BeanPropertyBindingResult(getTarget(),
				getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());

		if (this.conversionService != null) {
			result.initConversion(this.conversionService);
		}
		if (this.messageCodesResolver != null) {
			result.setMessageCodesResolver(this.messageCodesResolver);
		}

		return result;
	}

	/**
	 * Initialize direct field access for this DataBinder,
	 * as alternative to the default bean property access.
	 * @see #initBeanPropertyAccess()
	 * @see #createDirectFieldBindingResult()
	 */
	/**
	 *初始化此DataBinder的直接字段访问，
	 *作为默认bean属性访问的替代。
	 *@参见#initBeanPropertyAccess（）
	 *@参见#createDirectFieldBindingResult（）
	 */
	public void initDirectFieldAccess() {
		Assert.state(this.bindingResult == null,
				"DataBinder is already initialized - call initDirectFieldAccess before other configuration methods");
		this.directFieldAccess = true;
	}

	/**
	 * Create the {@link AbstractPropertyBindingResult} instance using direct
	 * field access.
	 * @since 4.2.1
	 */
	/**
	 *使用direct创建｛@link AbstractPropertyBindingResult｝实例
	 *字段访问。
	 *@自4.2.1起
	 */
	protected AbstractPropertyBindingResult createDirectFieldBindingResult() {
		DirectFieldBindingResult result = new DirectFieldBindingResult(getTarget(),
				getObjectName(), isAutoGrowNestedPaths());

		if (this.conversionService != null) {
			result.initConversion(this.conversionService);
		}
		if (this.messageCodesResolver != null) {
			result.setMessageCodesResolver(this.messageCodesResolver);
		}

		return result;
	}

	/**
	 * Return the internal BindingResult held by this DataBinder,
	 * as an AbstractPropertyBindingResult.
	 */
	/**
	 *返回此DataBinder持有的内部BindingResult，
	 *作为AbstractPropertyBindingResult。
	 */
	protected AbstractPropertyBindingResult getInternalBindingResult() {
		if (this.bindingResult == null) {
			this.bindingResult = (this.directFieldAccess ?
					createDirectFieldBindingResult(): createBeanPropertyBindingResult());
		}
		return this.bindingResult;
	}

	/**
	 * Return the underlying PropertyAccessor of this binder's BindingResult.
	 */
	/**
	 *返回此绑定程序的BindingResult的基础PropertyAccessor。
	 */
	protected ConfigurablePropertyAccessor getPropertyAccessor() {
		return getInternalBindingResult().getPropertyAccessor();
	}

	/**
	 * Return this binder's underlying SimpleTypeConverter.
	 */
	/**
	 *返回此绑定器的基础SimpleTypeConverter。
	 */
	protected SimpleTypeConverter getSimpleTypeConverter() {
		if (this.typeConverter == null) {
			this.typeConverter = new SimpleTypeConverter();
			if (this.conversionService != null) {
				this.typeConverter.setConversionService(this.conversionService);
			}
		}
		return this.typeConverter;
	}

	/**
	 * Return the underlying TypeConverter of this binder's BindingResult.
	 */
	/**
	 *返回此绑定程序的BindingResult的基础TypeConverter。
	 */
	protected PropertyEditorRegistry getPropertyEditorRegistry() {
		if (getTarget() != null) {
			return getInternalBindingResult().getPropertyAccessor();
		}
		else {
			return getSimpleTypeConverter();
		}
	}

	/**
	 * Return the underlying TypeConverter of this binder's BindingResult.
	 */
	/**
	 *返回此绑定程序的BindingResult的基础TypeConverter。
	 */
	protected TypeConverter getTypeConverter() {
		if (getTarget() != null) {
			return getInternalBindingResult().getPropertyAccessor();
		}
		else {
			return getSimpleTypeConverter();
		}
	}

	/**
	 * Return the BindingResult instance created by this DataBinder.
	 * This allows for convenient access to the binding results after
	 * a bind operation.
	 * @return the BindingResult instance, to be treated as BindingResult
	 * or as Errors instance (Errors is a super-interface of BindingResult)
	 * @see Errors
	 * @see #bind
	 */
	/**
	 *返回此DataBinder创建的BindingResult实例。
	 *这样可以方便地访问之后的绑定结果
	 *绑定操作。
	 *@返回BindingResult实例，作为BindingResult处理
	 
	 *@查看错误
	 *@见#bind
	 */
	public BindingResult getBindingResult() {
		return getInternalBindingResult();
	}


	/**
	 * Set whether to ignore unknown fields, that is, whether to ignore bind
	 * parameters that do not have corresponding fields in the target object.
	 * <p>Default is "true". Turn this off to enforce that all bind parameters
	 * must have a matching field in the target object.
	 * <p>Note that this setting only applies to <i>binding</i> operations
	 * on this DataBinder, not to <i>retrieving</i> values via its
	 * {@link #getBindingResult() BindingResult}.
	 * @see #bind
	 */
	/**
	 *设置是否忽略未知字段，即是否忽略绑定
	 *在目标对象中没有相应字段的参数。
	 *<p>默认值为“true”。关闭此选项可强制所有绑定参数
	 *必须在目标对象中具有匹配字段。
	 *<p>请注意，此设置仅适用于<i>绑定</i>操作
	 *在此DataBinder上，不允许<i>通过其
	 *｛@link#getBindingResult（）BindingResult｝。
	 *@见#bind
	 */
	public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
		this.ignoreUnknownFields = ignoreUnknownFields;
	}

	/**
	 * Return whether to ignore unknown fields when binding.
	 */
	/**
	 *返回绑定时是否忽略未知字段。
	 */
	public boolean isIgnoreUnknownFields() {
		return this.ignoreUnknownFields;
	}

	/**
	 * Set whether to ignore invalid fields, that is, whether to ignore bind
	 * parameters that have corresponding fields in the target object which are
	 * not accessible (for example because of null values in the nested path).
	 * <p>Default is "false". Turn this on to ignore bind parameters for
	 * nested objects in non-existing parts of the target object graph.
	 * <p>Note that this setting only applies to <i>binding</i> operations
	 * on this DataBinder, not to <i>retrieving</i> values via its
	 * {@link #getBindingResult() BindingResult}.
	 * @see #bind
	 */
	/**
	 *设置是否忽略无效字段，即是否忽略绑定
	 *在目标对象中具有相应字段的参数
	 *不可访问（例如，由于嵌套路径中的空值）。
	 *<p>默认值为“false”。启用此选项可忽略的绑定参数
	 *目标对象图中不存在的部分中的嵌套对象。
	 *<p>请注意，此设置仅适用于<i>绑定</i>操作
	 *在此DataBinder上，不允许<i>通过其
	 *｛@link#getBindingResult（）BindingResult｝。
	 *@见#bind
	 */
	public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
		this.ignoreInvalidFields = ignoreInvalidFields;
	}

	/**
	 * Return whether to ignore invalid fields when binding.
	 */
	/**
	 *返回绑定时是否忽略无效字段。
	 */
	public boolean isIgnoreInvalidFields() {
		return this.ignoreInvalidFields;
	}

	/**
	 * Register field patterns that should be allowed for binding.
	 * <p>Default is all fields.
	 * <p>Restrict this for example to avoid unwanted modifications by malicious
	 * users when binding HTTP request parameters.
	 * <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
	 * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
	 * well as direct equality.
	 * <p>The default implementation of this method stores allowed field patterns
	 * in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
	 * form. Subclasses which override this method must therefore take this into
	 * account.
	 * <p>More sophisticated matching can be implemented by overriding the
	 * {@link #isAllowed} method.
	 * <p>Alternatively, specify a list of <i>disallowed</i> field patterns.
	 * @param allowedFields array of allowed field patterns
	 * @see #setDisallowedFields
	 * @see #isAllowed(String)
	 */
	/**
	 *注册应该允许绑定的字段模式。
	 *＜p＞默认为所有字段。
	 *<p>例如，限制此操作以避免恶意进行不必要的修改
	 *用户绑定HTTP请求参数时。
	 *<p>支持{@code“xxx*”}、{@code”*xxx“}、{@code”*xxx*“}和
	 *｛@code“xxx*yyy”｝匹配（具有任意数量的图案部分），作为
	 *以及直接平等。
	 *<p>此方法的默认实现存储允许的字段模式
	 *在｛@linkplain PropertyAccessorUtils#canonicalPropertyName（String）canonical｝中
	 *因此，重写此方法的子类必须考虑到
	 *账户。
	 *<p>可以通过重写
	 *｛@link#isAllowed｝方法。
	 *<p>或者，指定一个<i>不允许的</i>字段模式列表。
	 *@param allowedFields允许字段模式的数组
	 *@参见#setDisabledFields
	 *@see#isAllowed（字符串）
	 */
	public void setAllowedFields(@Nullable String... allowedFields) {
		this.allowedFields = PropertyAccessorUtils.canonicalPropertyNames(allowedFields);
	}

	/**
	 * Return the field patterns that should be allowed for binding.
	 * @return array of allowed field patterns
	 * @see #setAllowedFields(String...)
	 */
	/**
	 *返回应该允许绑定的字段模式。
	 *@return允许的字段模式数组
	 *@参见#setAllowedFields（字符串…）
	 */
	@Nullable
	public String[] getAllowedFields() {
		return this.allowedFields;
	}

	/**
	 * Register field patterns that should <i>not</i> be allowed for binding.
	 * <p>Default is none.
	 * <p>Mark fields as disallowed, for example to avoid unwanted
	 * modifications by malicious users when binding HTTP request parameters.
	 * <p>Supports {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
	 * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
	 * well as direct equality.
	 * <p>The default implementation of this method stores disallowed field patterns
	 * in {@linkplain PropertyAccessorUtils#canonicalPropertyName(String) canonical}
	 * form. As of Spring Framework 5.2.21, the default implementation also transforms
	 * disallowed field patterns to {@linkplain String#toLowerCase() lowercase} to
	 * support case-insensitive pattern matching in {@link #isAllowed}. Subclasses
	 * which override this method must therefore take both of these transformations
	 * into account.
	 * <p>More sophisticated matching can be implemented by overriding the
	 * {@link #isAllowed} method.
	 * <p>Alternatively, specify a list of <i>allowed</i> field patterns.
	 * @param disallowedFields array of disallowed field patterns
	 * @see #setAllowedFields
	 * @see #isAllowed(String)
	 */
	/**
	 *注册应该允许＜i＞而不允许＜/i＞进行绑定的字段模式。
	 *<p>默认值为none。
	 *<p>将字段标记为不允许，例如，以避免不需要的字段
	 *恶意用户在绑定HTTP请求参数时进行的修改。
	 *<p>支持{@code“xxx*”}、{@code”*xxx“}、{@code”*xxx*“}和
	 *｛@code“xxx*yyy”｝匹配（具有任意数量的图案部分），作为
	 *以及直接平等。
	 *<p>此方法的默认实现存储不允许的字段模式
	 *在｛@linkplain PropertyAccessorUtils#canonicalPropertyName（String）canonical｝中
	 *从Spring Framework 5.2.21开始，默认实现也转换
	 *不允许的字段模式为｛@linkplain String#toLowerCase（）小写｝到
	 *在｛@link#isAllowed｝中支持不区分大小写的模式匹配。子类
	 *因此，覆盖该方法的必须同时进行这两种转换
	 *考虑在内。
	 *<p>可以通过重写
	 *｛@link#isAllowed｝方法。
	 *<p>或者，指定<i>允许的</i>字段模式的列表。
	 *@param disallowedFields不允许字段模式的数组
	 *@参见#setAllowedFields
	 *@see#isAllowed（字符串）
	 */
	public void setDisallowedFields(@Nullable String... disallowedFields) {
		if (disallowedFields == null) {
			this.disallowedFields = null;
		}
		else {
			String[] fieldPatterns = new String[disallowedFields.length];
			for (int i = 0; i < fieldPatterns.length; i++) {
				fieldPatterns[i] = PropertyAccessorUtils.canonicalPropertyName(disallowedFields[i]).toLowerCase();
			}
			this.disallowedFields = fieldPatterns;
		}
	}

	/**
	 * Return the field patterns that should <i>not</i> be allowed for binding.
	 * @return array of disallowed field patterns
	 * @see #setDisallowedFields(String...)
	 */
	/**
	 *返回应允许＜i＞而不允许＜/i＞进行绑定的字段模式。
	 *@return不允许的字段模式数组
	 *@参见#setDisabledFields（字符串…）
	 */
	@Nullable
	public String[] getDisallowedFields() {
		return this.disallowedFields;
	}

	/**
	 * Register fields that are required for each binding process.
	 * <p>If one of the specified fields is not contained in the list of
	 * incoming property values, a corresponding "missing field" error
	 * will be created, with error code "required" (by the default
	 * binding error processor).
	 * @param requiredFields array of field names
	 * @see #setBindingErrorProcessor
	 * @see DefaultBindingErrorProcessor#MISSING_FIELD_ERROR_CODE
	 */
	/**
	 *注册每个绑定过程所需的字段。
	 *＜p＞如果指定的字段之一未包含在
	 *传入的属性值，相应的“缺少字段”错误
	 *将被创建，错误代码为“required”（默认情况下
	 *绑定错误处理器）。
	 *@param requiredFields字段名称数组
	 *@参见#setBindingErrorProcessor
	 *@请参阅DefaultBindingErrorProcessor#MISSING_FIELD_ERROR_CODE
	 */
	public void setRequiredFields(@Nullable String... requiredFields) {
		this.requiredFields = PropertyAccessorUtils.canonicalPropertyNames(requiredFields);
		if (logger.isDebugEnabled()) {
			logger.debug("DataBinder requires binding of required fields [" +
					StringUtils.arrayToCommaDelimitedString(requiredFields) + "]");
		}
	}

	/**
	 * Return the fields that are required for each binding process.
	 * @return array of field names
	 */
	/**
	 *返回每个绑定过程所需的字段。
	 *@return字段名称数组
	 */
	@Nullable
	public String[] getRequiredFields() {
		return this.requiredFields;
	}

	/**
	 * Set the strategy to use for resolving errors into message codes.
	 * Applies the given strategy to the underlying errors holder.
	 * <p>Default is a DefaultMessageCodesResolver.
	 * @see BeanPropertyBindingResult#setMessageCodesResolver
	 * @see DefaultMessageCodesResolver
	 */
	/**
	 *设置用于将错误解析为消息代码的策略。
	 *将给定的策略应用于潜在错误持有者。
	 *<p>Default是DefaultMessageCodesResolver。
	 *@see BeanProperty绑定结果#setMessageCodesResolver
	 *@请参阅DefaultMessageCodesResolver
	 */
	public void setMessageCodesResolver(@Nullable MessageCodesResolver messageCodesResolver) {
		Assert.state(this.messageCodesResolver == null, "DataBinder is already initialized with MessageCodesResolver");
		this.messageCodesResolver = messageCodesResolver;
		if (this.bindingResult != null && messageCodesResolver != null) {
			this.bindingResult.setMessageCodesResolver(messageCodesResolver);
		}
	}

	/**
	 * Set the strategy to use for processing binding errors, that is,
	 * required field errors and {@code PropertyAccessException}s.
	 * <p>Default is a DefaultBindingErrorProcessor.
	 * @see DefaultBindingErrorProcessor
	 */
	/**
	 *设置用于处理绑定错误的策略，即，
	 *必需的字段错误和｛@code PropertyAccessException｝s。
	 *＜p＞默认值是DefaultBindingErrorProcessor。
	 *@请参阅DefaultBindingErrorProcessor
	 */
	public void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) {
		Assert.notNull(bindingErrorProcessor, "BindingErrorProcessor must not be null");
		this.bindingErrorProcessor = bindingErrorProcessor;
	}

	/**
	 * Return the strategy for processing binding errors.
	 */
	/**
	 *返回处理绑定错误的策略。
	 */
	public BindingErrorProcessor getBindingErrorProcessor() {
		return this.bindingErrorProcessor;
	}

	/**
	 * Set the Validator to apply after each binding step.
	 * @see #addValidators(Validator...)
	 * @see #replaceValidators(Validator...)
	 */
	/**
	 *将Validator设置为在每个绑定步骤后应用。
	 *@见#addValidators（验证程序…）
	 *@请参阅#replaceValidators（验证程序…）
	 */
	public void setValidator(@Nullable Validator validator) {
		assertValidators(validator);
		this.validators.clear();
		if (validator != null) {
			this.validators.add(validator);
		}
	}

	private void assertValidators(Validator... validators) {
		Object target = getTarget();
		for (Validator validator : validators) {
			if (validator != null && (target != null && !validator.supports(target.getClass()))) {
				throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + target);
			}
		}
	}

	/**
	 * Add Validators to apply after each binding step.
	 * @see #setValidator(Validator)
	 * @see #replaceValidators(Validator...)
	 */
	/**
	 *在每个绑定步骤后添加要应用的验证程序。
	 *@参见#setValidator（验证程序）
	 *@请参阅#replaceValidators（验证程序…）
	 */
	public void addValidators(Validator... validators) {
		assertValidators(validators);
		this.validators.addAll(Arrays.asList(validators));
	}

	/**
	 * Replace the Validators to apply after each binding step.
	 * @see #setValidator(Validator)
	 * @see #addValidators(Validator...)
	 */
	/**
	 *更换每个绑定步骤后要应用的验证程序。
	 *@参见#setValidator（验证程序）
	 *@见#addValidators（验证程序…）
	 */
	public void replaceValidators(Validator... validators) {
		assertValidators(validators);
		this.validators.clear();
		this.validators.addAll(Arrays.asList(validators));
	}

	/**
	 * Return the primary Validator to apply after each binding step, if any.
	 */
	/**
	 *在每个绑定步骤后返回要应用的主验证程序（如果有）。
	 */
	@Nullable
	public Validator getValidator() {
		return (!this.validators.isEmpty() ? this.validators.get(0) : null);
	}

	/**
	 * Return the Validators to apply after data binding.
	 */
	/**
	 *返回要在数据绑定后应用的验证程序。
	 */
	public List<Validator> getValidators() {
		return Collections.unmodifiableList(this.validators);
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Implementation of PropertyEditorRegistry/TypeConverter interface
	// PropertyEditorRegistry/TypeConverter接口的实现
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	/**
	 * Specify a {@link ConversionService} to use for converting
	 * property values, as an alternative to JavaBeans PropertyEditors.
	 */
	/**
	 *指定用于转换的｛@link ConversionService｝
	 *属性值，作为JavaBeans PropertyEditors的替代方案。
	 */
	public void setConversionService(@Nullable ConversionService conversionService) {
		Assert.state(this.conversionService == null, "DataBinder is already initialized with ConversionService");
		this.conversionService = conversionService;
		if (this.bindingResult != null && conversionService != null) {
			this.bindingResult.initConversion(conversionService);
		}
	}

	/**
	 * Return the associated ConversionService, if any.
	 */
	/**
	 *返回关联的ConversionService（如果有）。
	 */
	@Nullable
	public ConversionService getConversionService() {
		return this.conversionService;
	}

	/**
	 * Add a custom formatter, applying it to all fields matching the
	 * {@link Formatter}-declared type.
	 * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
	 * @param formatter the formatter to add, generically declared for a specific type
	 * @since 4.2
	 * @see #registerCustomEditor(Class, PropertyEditor)
	 */
	/**
	 *添加自定义格式化程序，将其应用于与
	 *｛@link Formatter｝-声明的类型。
	 *<p>在封面下面注册相应的｛@link PropertyEditor｝适配器。
	 *@param formatter要添加的格式化程序，一般为特定类型声明
	 *@自4.2起
	 *@参见#registerCustomEditor（类，PropertyEditor）
	 */
	public void addCustomFormatter(Formatter<?> formatter) {
		FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
		getPropertyEditorRegistry().registerCustomEditor(adapter.getFieldType(), adapter);
	}

	/**
	 * Add a custom formatter for the field type specified in {@link Formatter} class,
	 * applying it to the specified fields only, if any, or otherwise to all fields.
	 * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
	 * @param formatter the formatter to add, generically declared for a specific type
	 * @param fields the fields to apply the formatter to, or none if to be applied to all
	 * @since 4.2
	 * @see #registerCustomEditor(Class, String, PropertyEditor)
	 */
	/**
	 *为｛@link formatter｝类中指定的字段类型添加自定义格式化程序，
	 *仅将其应用于指定的字段（如果有），或以其他方式应用于所有字段。
	 *<p>在封面下面注册相应的｛@link PropertyEditor｝适配器。
	 *@param formatter要添加的格式化程序，一般为特定类型声明
	 *@param fields要应用格式化程序的字段，如果要应用于所有字段，则为none
	 *@自4.2起
	 *@参见#registerCustomEditor（类、字符串、属性编辑器）
	 */
	public void addCustomFormatter(Formatter<?> formatter, String... fields) {
		FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
		Class<?> fieldType = adapter.getFieldType();
		if (ObjectUtils.isEmpty(fields)) {
			getPropertyEditorRegistry().registerCustomEditor(fieldType, adapter);
		}
		else {
			for (String field : fields) {
				getPropertyEditorRegistry().registerCustomEditor(fieldType, field, adapter);
			}
		}
	}

	/**
	 * Add a custom formatter, applying it to the specified field types only, if any,
	 * or otherwise to all fields matching the {@link Formatter}-declared type.
	 * <p>Registers a corresponding {@link PropertyEditor} adapter underneath the covers.
	 * @param formatter the formatter to add (does not need to generically declare a
	 * field type if field types are explicitly specified as parameters)
	 * @param fieldTypes the field types to apply the formatter to, or none if to be
	 * derived from the given {@link Formatter} implementation class
	 * @since 4.2
	 * @see #registerCustomEditor(Class, PropertyEditor)
	 */
	/**
	 *添加自定义格式化程序，仅将其应用于指定的字段类型（如果有的话），
	 *或者以其他方式添加到与｛@link Formatter｝声明的类型匹配的所有字段。
	 *<p>在封面下面注册相应的｛@link PropertyEditor｝适配器。
	 *@param formatter要添加的格式化程序（不需要一般地声明
	 *字段类型（如果字段类型被明确指定为参数）
	 *@param fieldTypes要应用格式化程序的字段类型，如果要，则为none
	 *派生自给定的｛@link Formatter｝实现类
	 *@自4.2起
	 *@参见#registerCustomEditor（类，PropertyEditor）
	 */
	public void addCustomFormatter(Formatter<?> formatter, Class<?>... fieldTypes) {
		FormatterPropertyEditorAdapter adapter = new FormatterPropertyEditorAdapter(formatter);
		if (ObjectUtils.isEmpty(fieldTypes)) {
			getPropertyEditorRegistry().registerCustomEditor(adapter.getFieldType(), adapter);
		}
		else {
			for (Class<?> fieldType : fieldTypes) {
				getPropertyEditorRegistry().registerCustomEditor(fieldType, adapter);
			}
		}
	}

	@Override
	public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
		getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor);
	}

	@Override
	public void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String field, PropertyEditor propertyEditor) {
		getPropertyEditorRegistry().registerCustomEditor(requiredType, field, propertyEditor);
	}

	@Override
	@Nullable
	public PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath) {
		return getPropertyEditorRegistry().findCustomEditor(requiredType, propertyPath);
	}

	@Override
	@Nullable
	public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException {
		return getTypeConverter().convertIfNecessary(value, requiredType);
	}

	@Override
	@Nullable
	public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
			@Nullable MethodParameter methodParam) throws TypeMismatchException {

		return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
	}

	@Override
	@Nullable
	public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
			throws TypeMismatchException {

		return getTypeConverter().convertIfNecessary(value, requiredType, field);
	}

	@Nullable
	@Override
	public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
			@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {

		return getTypeConverter().convertIfNecessary(value, requiredType, typeDescriptor);
	}


	/**
	 * Bind the given property values to this binder's target.
	 * <p>This call can create field errors, representing basic binding
	 * errors like a required field (code "required"), or type mismatch
	 * between value and bean property (code "typeMismatch").
	 * <p>Note that the given PropertyValues should be a throwaway instance:
	 * For efficiency, it will be modified to just contain allowed fields if it
	 * implements the MutablePropertyValues interface; else, an internal mutable
	 * copy will be created for this purpose. Pass in a copy of the PropertyValues
	 * if you want your original instance to stay unmodified in any case.
	 * @param pvs property values to bind
	 * @see #doBind(org.springframework.beans.MutablePropertyValues)
	 */
	/**
	 *将给定的属性值绑定到此绑定器的目标。
	 *<p>此调用可能会创建表示基本绑定的字段错误
	 *错误，如必填字段（代码“required”）或类型不匹配
	 *值和bean属性之间（代码“typeMismatch”）。
	 *<p>请注意，给定的PropertyValues应该是一次性实例：
	 *为了提高效率，如果
	 *实现了MutablePropertyValues接口；否则，内部可变
	 *将为此目的创建副本。传入PropertyValues的副本
	 *如果您希望您的原始实例在任何情况下都保持不变。
	 *@param要绑定的pvs属性值
	 *@见#doBind（org.springframework.beans.MutablePropertyValues）
	 */
	public void bind(PropertyValues pvs) {
		MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues ?
				(MutablePropertyValues) pvs : new MutablePropertyValues(pvs));
		doBind(mpvs);
	}

	/**
	 * Actual implementation of the binding process, working with the
	 * passed-in MutablePropertyValues instance.
	 * @param mpvs the property values to bind,
	 * as MutablePropertyValues instance
	 * @see #checkAllowedFields
	 * @see #checkRequiredFields
	 * @see #applyPropertyValues
	 */
	/**
	 *实际执行绑定过程，与
	 *在MutablePropertyValues实例中传递。
	 *@param mpvs要绑定的属性值，
	 *作为MutablePropertyValues实例
	 *@参见#checkAllowedFields
	 *@参见#checkRequiredFields
	 *@参见#applyPropertyValues
	 */
	protected void doBind(MutablePropertyValues mpvs) {
		checkAllowedFields(mpvs);
		checkRequiredFields(mpvs);
		applyPropertyValues(mpvs);
	}

	/**
	 * Check the given property values against the allowed fields,
	 * removing values for fields that are not allowed.
	 * @param mpvs the property values to be bound (can be modified)
	 * @see #getAllowedFields
	 * @see #isAllowed(String)
	 */
	/**
	 *对照允许的字段检查给定的属性值，
	 *删除不允许的字段的值。
	 *@param mpvs要绑定的属性值（可以修改）
	 *@参见#getAllowedFields
	 *@see#isAllowed（字符串）
	 */
	protected void checkAllowedFields(MutablePropertyValues mpvs) {
		PropertyValue[] pvs = mpvs.getPropertyValues();
		for (PropertyValue pv : pvs) {
			String field = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
			if (!isAllowed(field)) {
				mpvs.removePropertyValue(pv);
				getBindingResult().recordSuppressedField(field);
				if (logger.isDebugEnabled()) {
					logger.debug("Field [" + field + "] has been removed from PropertyValues " +
							"and will not be bound, because it has not been found in the list of allowed fields");
				}
			}
		}
	}

	/**
	 * Determine if the given field is allowed for binding.
	 * <p>Invoked for each passed-in property value.
	 * <p>Checks for {@code "xxx*"}, {@code "*xxx"}, {@code "*xxx*"}, and
	 * {@code "xxx*yyy"} matches (with an arbitrary number of pattern parts), as
	 * well as direct equality, in the configured lists of allowed field patterns
	 * and disallowed field patterns.
	 * <p>Matching against allowed field patterns is case-sensitive; whereas,
	 * matching against disallowed field patterns is case-insensitive.
	 * <p>A field matching a disallowed pattern will not be accepted even if it
	 * also happens to match a pattern in the allowed list.
	 * <p>Can be overridden in subclasses, but care must be taken to honor the
	 * aforementioned contract.
	 * @param field the field to check
	 * @return {@code true} if the field is allowed
	 * @see #setAllowedFields
	 * @see #setDisallowedFields
	 * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
	 */
	/**
	 *确定是否允许对给定字段进行绑定。
	 *<p>为每个传入的属性值调用。
	 *<p>检查｛@code“xxx*”｝、｛@ccode“*xxx”｝和
	 *｛@code“xxx*yyy”｝匹配（具有任意数量的图案部分），作为
	 *以及直接相等，在已配置的允许字段模式列表中
	 *以及不允许的字段模式。
	 *<p>与允许的字段模式匹配区分大小写；鉴于
	 *与不允许的字段模式匹配是不区分大小写的。
	 *<p>与不允许的模式匹配的字段将不被接受，即使它
	 *也恰好与允许列表中的模式相匹配。
	 *＜p＞可以在子类中重写，但必须注意遵守
	 *上述合同。
	 *@param字段要检查的字段
	 *@return｛@code true｝如果字段是允许的
	 *@参见#setAllowedFields
	 *@参见#setDisabledFields
	 *@see.org.springframework.util.PatternMatchUtils#simpleMatch（字符串，字符串）
	 */
	protected boolean isAllowed(String field) {
		String[] allowed = getAllowedFields();
		String[] disallowed = getDisallowedFields();
		return ((ObjectUtils.isEmpty(allowed) || PatternMatchUtils.simpleMatch(allowed, field)) &&
				(ObjectUtils.isEmpty(disallowed) || !PatternMatchUtils.simpleMatch(disallowed, field.toLowerCase())));
	}

	/**
	 * Check the given property values against the required fields,
	 * generating missing field errors where appropriate.
	 * @param mpvs the property values to be bound (can be modified)
	 * @see #getRequiredFields
	 * @see #getBindingErrorProcessor
	 * @see BindingErrorProcessor#processMissingFieldError
	 */
	/**
	 *对照所需字段检查给定的属性值，
	 *在适当的情况下生成漏字段错误。
	 *@param mpvs要绑定的属性值（可以修改）
	 *@参见#getRequiredFields
	 *@参见#getBindingErrorProcessor
	 *@请参阅BindingErrorProcessor#processMissingFieldError
	 */
	protected void checkRequiredFields(MutablePropertyValues mpvs) {
		String[] requiredFields = getRequiredFields();
		if (!ObjectUtils.isEmpty(requiredFields)) {
			Map<String, PropertyValue> propertyValues = new HashMap<>();
			PropertyValue[] pvs = mpvs.getPropertyValues();
			for (PropertyValue pv : pvs) {
				String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
				propertyValues.put(canonicalName, pv);
			}
			for (String field : requiredFields) {
				PropertyValue pv = propertyValues.get(field);
				boolean empty = (pv == null || pv.getValue() == null);
				if (!empty) {
					if (pv.getValue() instanceof String) {
						empty = !StringUtils.hasText((String) pv.getValue());
					}
					else if (pv.getValue() instanceof String[] values) {
						empty = (values.length == 0 || !StringUtils.hasText(values[0]));
					}
				}
				if (empty) {
					// Use bind error processor to create FieldError.
					// 使用绑定错误处理器创建FieldError。
					getBindingErrorProcessor().processMissingFieldError(field, getInternalBindingResult());
					// Remove property from property values to bind:
					// 从要绑定的属性值中删除属性：
					// It has already caused a field error with a rejected value.
					// 它已经导致了一个具有被拒绝值的字段错误。
					if (pv != null) {
						mpvs.removePropertyValue(pv);
						propertyValues.remove(field);
					}
				}
			}
		}
	}

	/**
	 * Apply given property values to the target object.
	 * <p>Default implementation applies all the supplied property
	 * values as bean property values. By default, unknown fields will
	 * be ignored.
	 * @param mpvs the property values to be bound (can be modified)
	 * @see #getTarget
	 * @see #getPropertyAccessor
	 * @see #isIgnoreUnknownFields
	 * @see #getBindingErrorProcessor
	 * @see BindingErrorProcessor#processPropertyAccessException
	 */
	/**
	 *将给定的属性值应用于目标对象。
	 *＜p＞默认实现应用所有提供的属性
	 *值作为bean属性值。默认情况下，未知字段将
	 *被忽略。
	 *@param mpvs要绑定的属性值（可以修改）
	 *@参见#getTarget
	 *@参见#getPropertyAccessor
	 *@参见#isIgnoreUnknownFields
	 *@参见#getBindingErrorProcessor
	 *@请参阅BindingErrorProcessor#processPropertyAccessException
	 */
	protected void applyPropertyValues(MutablePropertyValues mpvs) {
		try {
			// Bind request parameters onto target object.
			// 将请求参数绑定到目标对象上。
			getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
		}
		catch (PropertyBatchUpdateException ex) {
			// Use bind error processor to create FieldErrors.
			// 使用绑定错误处理器创建FieldErrors。
			for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
				getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
			}
		}
	}


	/**
	 * Invoke the specified Validators, if any.
	 * @see #setValidator(Validator)
	 * @see #getBindingResult()
	 */
	/**
	 *调用指定的验证程序（如果有）。
	 *@参见#setValidator（验证程序）
	 *@参见#getBindingResult（）
	 */
	public void validate() {
		Object target = getTarget();
		Assert.state(target != null, "No target to validate");
		BindingResult bindingResult = getBindingResult();
		// Call each validator with the same binding result
		// 使用相同的绑定结果调用每个验证器
		for (Validator validator : getValidators()) {
			validator.validate(target, bindingResult);
		}
	}

	/**
	 * Invoke the specified Validators, if any, with the given validation hints.
	 * <p>Note: Validation hints may get ignored by the actual target Validator.
	 * @param validationHints one or more hint objects to be passed to a {@link SmartValidator}
	 * @since 3.1
	 * @see #setValidator(Validator)
	 * @see SmartValidator#validate(Object, Errors, Object...)
	 */
	/**
	 *使用给定的验证提示调用指定的验证程序（如果有的话）。
	 *<p>注意：实际目标验证程序可能会忽略验证提示。
	 *@param validationHints要传递给｛@link SmartValidator｝的一个或多个提示对象
	 *@自3.1起
	 *@参见#setValidator（验证程序）
	 *@请参阅SmartValidator#validate（对象、错误、对象…）
	 */
	public void validate(Object... validationHints) {
		Object target = getTarget();
		Assert.state(target != null, "No target to validate");
		BindingResult bindingResult = getBindingResult();
		// Call each validator with the same binding result
		// 使用相同的绑定结果调用每个验证器
		for (Validator validator : getValidators()) {
			if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
				((SmartValidator) validator).validate(target, bindingResult, validationHints);
			}
			else if (validator != null) {
				validator.validate(target, bindingResult);
			}
		}
	}

	/**
	 * Close this DataBinder, which may result in throwing
	 * a BindException if it encountered any errors.
	 * @return the model Map, containing target object and Errors instance
	 * @throws BindException if there were any errors in the bind operation
	 * @see BindingResult#getModel()
	 */
	/**
	 *关闭此DataBinder，这可能导致引发
	 *如果遇到任何错误，则返回BindException。
	 *@返回模型Map，包含目标对象和Errors实例
	 *如果绑定操作中有任何错误，@throws BindException
	 *@参见BindingResult#getModel（）
	 */
	public Map<?, ?> close() throws BindException {
		if (getBindingResult().hasErrors()) {
			throw new BindException(getBindingResult());
		}
		return getBindingResult().getModel();
	}

}
